Skip to content

feat(wasm-utxo): redesign PSBT signing API for clarity and performance#116

Merged
OttoAllmendinger merged 2 commits intomasterfrom
BTC-2980.fix-signing
Jan 28, 2026
Merged

feat(wasm-utxo): redesign PSBT signing API for clarity and performance#116
OttoAllmendinger merged 2 commits intomasterfrom
BTC-2980.fix-signing

Conversation

@OttoAllmendinger
Copy link
Contributor

This PR introduces a comprehensive redesign of the PSBT signing API to improve
clarity and performance, along with benchmarking tools to measure the impact.

Changes

  • Redesigned WASM/Rust API that explicitly communicates method behavior and
    performance implications
  • Implemented efficient bulk signing for MuSig2 inputs with SighashCache reuse,
    resulting in 2x performance improvement
  • Added clear type-specific signing methods to replace the misleading API
  • Created comprehensive benchmarking for PSBT signing across different script
    types and input counts

New WASM API (backward compatible)

  • is_musig2_input(index) - Check if input is MuSig2 keypath
  • sign_all_wallet_inputs(xpriv) - Bulk sign ECDSA/Schnorr script path
  • sign_wallet_input(index, xpriv) - Single input with save/restore
  • sign_musig2_input(index, xpriv) - Single MuSig2 input
  • sign_all_musig2_inputs(xpriv) - Bulk MuSig2 with SighashCache reuse
  • sign_replay_protection_inputs(ecpair) - Bulk replay protection

Performance Improvements

MuSig2 bulk signing now shows ~4.5ms per input (down from ~9.5ms),
representing a 2x improvement by reusing the SighashCache.

BTC-2980

OttoAllmendinger and others added 2 commits January 28, 2026 15:22
Add a comprehensive benchmark for comparing bulk vs per-input signing
performance across different script types (p2sh, p2shP2wsh, p2wsh,
p2trLegacy, p2trMusig2KeyPath) with varying input counts.

Co-authored-by: llm-git <llm-git@ttll.de>
Problem:
The previous signing API had several issues:
1. `signInput(index, key)` claimed to sign only one input but actually
   signed ALL inputs internally (for ECDSA), which was misleading
2. MuSig2 bulk signing was inefficient - it recreated SighashCache for
   each input, recomputing sha_prevouts, sha_amounts, sha_scriptpubkeys,
   sha_sequences, and sha_outputs redundantly
3. The API didn't clearly communicate performance characteristics

Solution:
Implement an honest, clean WASM/Rust API that explicitly communicates
what each method does and its performance implications.

New WASM API (backward compatible - old methods kept as deprecated):
- is_musig2_input(index) - check if input is MuSig2 keypath
- sign_all_wallet_inputs(xpriv) - bulk sign ECDSA/Schnorr script path
- sign_wallet_input(index, xpriv) - single input with save/restore
  (documented as NOT faster than bulk)
- sign_musig2_input(index, xpriv) - single MuSig2 input
- sign_all_musig2_inputs(xpriv) - NEW: bulk MuSig2 with SighashCache
  reuse for 2x performance improvement
- sign_replay_protection_inputs(ecpair) - bulk replay protection

TypeScript changes:
- Added isBIP32Arg() type guard to js/bip32.ts
- Updated sign(key) to call both sign_all_wallet_inputs and
  sign_all_musig2_inputs for optimal bulk performance
- Updated signInput() to route to appropriate method based on input type

Rust changes:
- Added sign_with_first_round_and_cache() to Musig2Context that accepts
  external SighashCache and prevouts for efficient batch MuSig2 signing
- Added corresponding wrapper in BitGoPsbt

Performance results (1000 inputs):
- ECDSA bulk: ~1.7ms per input (unchanged)
- MuSig2 bulk: ~4.5ms per input (was ~9.5ms - 2x improvement!)

The MuSig2 improvement comes from reusing SighashCache which caches
the shared BIP-341 sighash components across all inputs.

Issue: BTC-2980
@OttoAllmendinger OttoAllmendinger marked this pull request as ready for review January 28, 2026 14:37
@OttoAllmendinger OttoAllmendinger requested a review from a team as a code owner January 28, 2026 14:37
@OttoAllmendinger OttoAllmendinger merged commit 2b9bc51 into master Jan 28, 2026
6 checks passed
@OttoAllmendinger OttoAllmendinger deleted the BTC-2980.fix-signing branch January 28, 2026 15:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants